package org.fanjr.simplify.rest.storage;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.fanjr.simplify.rest.SkipMapping;
import org.fanjr.simplify.rest.exceptions.SimplifyRuntimeException;
import org.fanjr.simplify.rest.utils.SimplifyCounterUtil;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 
 * @author fanjr@vip.qq.com
 * @since 20190222 10:29:28
 */
public class SimplifyMappingStorage extends SimplifyStorage<Class<?>, Map<Method, String>> {
	public final static SimplifyMappingStorage INSTANCE = new SimplifyMappingStorage();

	private SimplifyMappingStorage() {
		// skip
	}

	public Map<Method, String> resolvPathByType(Class<?> type, Set<Class<?>> inters) {
		return buildAndGet(type, inters);
	}

	@Override
	protected Map<Method, String> buildFunction(Class<?> type, Object[] args) {
		@SuppressWarnings("unchecked")
		Set<Class<?>> inters = (Set<Class<?>>) args[0];
		Set<Method> targetMthods = new HashSet<>();

		if (!type.isInterface()) {
			if (inters.size() > 0) {
				for (Class<?> inter : inters) {
					for (Method m : inter.getMethods()) {
						try {
							m = type.getMethod(m.getName(), m.getParameterTypes());
							if (null == AnnotationUtils.findAnnotation(m, RequestMapping.class)
									&& null == AnnotationUtils.findAnnotation(m, SkipMapping.class)) {
								targetMthods.add(m);
							}
						} catch (Exception e) {
							throw new SimplifyRuntimeException(e);
						}
					}
				}
			} else {
				for (Method m : type.getMethods()) {
					if (m.getDeclaringClass() == Object.class || Modifier.isStatic(m.getModifiers())) {
						continue;
					}
					if (null == AnnotationUtils.findAnnotation(m, RequestMapping.class)
							&& null == AnnotationUtils.findAnnotation(m, SkipMapping.class)) {
						targetMthods.add(m);
					}
				}
			}
		}

		Map<Method, String> mapping = new HashMap<Method, String>();
		Map<String, Method> sortMap = new HashMap<String, Method>();
		for (Method method : targetMthods) {
			sortMap.put(method.toGenericString(), method);
		}
		SimplifyCounterUtil counter = SimplifyCounterUtil.newInstance();
		for (Entry<String, Method> entry : sortMap.entrySet()) {
			Method method = entry.getValue();
			int num = counter.add(method.getName());
			if (num == 1) {
				mapping.put(method, method.getName());
			} else {
				mapping.put(method, method.getName() + (num - 1));
			}
		}
		return mapping;
	}
}